<!--
  组件：ChargeItemBatchDialog
  描述：费用项目批量选择弹窗，支持搜索、全选、移除、确认与取消；显示总金额。
  Props：
    - modelValue(Boolean)：弹窗显示/隐藏（v-model）
    - title(String)：弹窗标题，默认“批量选择费用项目”
    - loading(Boolean)：费用项目列表加载中状态
    - items(Array)：费用项目列表（由父组件提供）
    - initialSelected(Array)：初始已选项目列表（由父组件提供）
  Emits：
    - update:modelValue(Boolean)：用于关闭弹窗
    - confirm(Array)：确认选择，返回选中的费用项目列表
    - cancel()：取消选择
    - selected-change(Array)：当选择列表变化时触发
    - search(String)：输入搜索关键字时触发（父组件可选择远程搜索）
  Slots：
    - header：自定义头部区域
    - footer：自定义底部区域（默认提供“取消 / 确定”按钮）
    - item-extra：项目行右侧扩展区域（例如展示单位、频次等）
-->
<template>
  <el-dialog
    v-model="innerVisible"
    :title="title"
    width="720px"
    :close-on-click-modal="false"
    class="charge-item-dialog"
  >
    <div class="dialog-content">
      <!-- 搜索与全选 -->
      <div class="toolbar">
        <el-input
          v-model="keyWord"
          placeholder="输入项目名称快速查找"
          prefix-icon="Search"
          clearable
          @input="onSearch"
          class="search-input"
        />
      </div>

      <!-- 费用项目列表 -->
      <div class="list-section" v-loading="loading">
        <div class="charge-list">
          <div
            v-for="item in filteredItems"
            :key="item.treatmentId"
            class="charge-item-row"
            :class="{ selected: tempSelected.some(ci => ci.treatmentId === item.treatmentId) }"
            @click="toggleChargeItem(item)"
          >
            <el-checkbox
              :model-value="tempSelected.some(ci => ci.treatmentId === item.treatmentId)"
              @change="toggleChargeItem(item)"
              class="charge-checkbox"
            />
            <div class="charge-item-info">
              <div class="charge-item-name">{{ item.treatmentName }}</div>
              <div class="charge-item-details">
                单价：{{ Number(item.sellingPrice ?? 0).toFixed(2) }} 元 · 单位：{{ item.treatmentUnit || '-' }}
              </div>
            </div>
            <!-- 右侧扩展槽位 -->
            <slot name="item-extra" :item="item" />
            <el-button
              text
              type="danger"
              class="remove-btn"
              @click.stop="removeSelectedItem(item)"
              v-if="tempSelected.some(ci => ci.treatmentId === item.treatmentId)"
              >移除</el-button
            >
          </div>
        </div>

        <!-- 已选列表与汇总 -->
        <div class="selected-section">
          <div class="selected-header">
            已选 {{ tempSelected.length }} 项，总金额：
            <span class="total-amount">{{ totalAmountLabel }}</span>
          </div>
          <div class="selected-list">
            <el-tag
              v-for="s in tempSelected"
              :key="s.treatmentId"
              closable
              @close="removeSelectedItem(s)"
              class="selected-tag"
              >{{ s.treatmentName }}</el-tag
            >
          </div>
        </div>
      </div>
    </div>

    <template #footer>
      <slot name="footer">
        <div class="dialog-footer">
          <el-button @click="handleCancel">取消</el-button>
          <el-button type="primary" @click="handleConfirm"> 确定 </el-button>
        </div>
      </slot>
    </template>
  </el-dialog>
</template>

<script setup>
// 中文注释：该组件管理临时选择、搜索与全选逻辑，并计算总金额
import { ref, watch, computed } from 'vue'
import { calculateTotalAmount } from './utils/chargeItemUtils'

const props = defineProps({
  modelValue: { type: Boolean, default: false },
  title: { type: String, default: '批量选择费用项目' },
  loading: { type: Boolean, default: false },
  items: { type: Array, default: () => [] },
  initialSelected: { type: Array, default: () => [] }
})

const emit = defineEmits(['update:modelValue', 'confirm', 'cancel', 'selected-change', 'search'])

const innerVisible = ref(props.modelValue)
watch(
  () => props.modelValue,
  v => {
    innerVisible.value = v
    if (v) {
      tempSelected.value = [...props.initialSelected]
      keyWord.value = ''
      filteredItems.value = [...props.items]
    }
  }
)
watch(innerVisible, v => emit('update:modelValue', v))

const keyWord = ref('')
const filteredItems = ref([...props.items])
watch(
  () => props.items,
  list => {
    filteredItems.value = [...list]
  }
)

const tempSelected = ref([...props.initialSelected])

// 计算：全选与不确定状态
const isAllSelected = computed(() => {
  if (!filteredItems.value.length) return false
  return filteredItems.value.every(i => tempSelected.value.some(s => s.treatmentId === i.treatmentId))
})
const isIndeterminate = computed(() => {
  const count = filteredItems.value.filter(i => tempSelected.value.some(s => s.treatmentId === i.treatmentId)).length
  return count > 0 && count < filteredItems.value.length
})

// 计算：总金额标签
const totalAmountLabel = computed(() => {
  const total = calculateTotalAmount(tempSelected.value)
  return `${total.toFixed(2)} 元`
})

// 方法：搜索
const onSearch = () => {
  const k = keyWord.value.trim()
  emit('search', k)
  if (!k) {
    filteredItems.value = [...props.items]
    return
  }
  filteredItems.value = props.items.filter(
    i => String(i.treatmentName || '').includes(k) || String(i.code || '').includes(k)
  )
}

// 方法：切换选择
const toggleChargeItem = item => {
  const idx = tempSelected.value.findIndex(ci => ci.treatmentId === item.treatmentId)
  if (idx > -1) {
    tempSelected.value.splice(idx, 1)
  } else {
    tempSelected.value.push(item)
  }
  emit('selected-change', [...tempSelected.value])
}

// 方法：全选当前筛选
const handleSelectAll = checked => {
  if (checked) {
    const idSet = new Set(tempSelected.value.map(s => s.treatmentId))
    filteredItems.value.forEach(i => {
      if (!idSet.has(i.treatmentId)) tempSelected.value.push(i)
    })
  } else {
    const filteredIds = new Set(filteredItems.value.map(i => i.treatmentId))
    tempSelected.value = tempSelected.value.filter(s => !filteredIds.has(s.treatmentId))
  }
  emit('selected-change', [...tempSelected.value])
}

// 方法：移除单项
const removeSelectedItem = item => {
  const idx = tempSelected.value.findIndex(ci => ci.treatmentId === item.treatmentId)
  if (idx > -1) {
    tempSelected.value.splice(idx, 1)
    emit('selected-change', [...tempSelected.value])
  }
}

// 方法：确认与取消
const handleConfirm = () => {
  emit('confirm', [...tempSelected.value])
  innerVisible.value = false
}
const handleCancel = () => {
  tempSelected.value = [...props.initialSelected]
  innerVisible.value = false
  emit('cancel')
}
</script>

<style lang="scss" scoped>
.charge-item-dialog {
  .dialog-content {
    display: flex;
    flex-direction: column;
    gap: 12px;
  }

  .toolbar {
    display: flex;
    align-items: center;
    gap: 12px;

    .search-input {
      flex: 1;
    }
    .select-all {
      white-space: nowrap;
    }
  }

  .list-section {
    display: grid;
    grid-template-columns: 1fr;
    gap: 12px;
  }

  .charge-list {
    max-height: 360px;
    overflow: auto;
    border: 1px solid var(--el-border-color);
    border-radius: 6px;
    padding: 6px;

    .charge-item-row {
      display: flex;
      align-items: center;
      padding: 8px;
      border-radius: 6px;
      cursor: pointer;

      &:hover {
        background-color: var(--el-fill-color-light);
      }

      &.selected {
        background-color: var(--el-color-primary-light-9);
      }

      .charge-checkbox {
        margin-right: 8px;
      }

      .charge-item-info {
        display: flex;
        flex-direction: column;
        gap: 2px;
        flex: 1;

        .charge-item-name {
          font-weight: 600;
        }
        .charge-item-details {
          font-size: 12px;
          color: var(--el-text-color-secondary);
        }
      }

      .remove-btn {
        margin-left: 8px;
      }
    }
  }

  .selected-section {
    .selected-header {
      font-size: 12px;
      color: var(--el-text-color-secondary);
      .total-amount {
        color: var(--el-color-primary);
        font-weight: 600;
      }
    }
    .selected-list {
      display: flex;
      flex-wrap: wrap;
      margin-top: 8px;
      gap: 8px;
      .selected-tag {
        margin-right: 4px;
      }
    }
  }

  .dialog-footer {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
  }
}
</style>
